package org.budo.selenium.phantomjs;

import java.io.File;
import java.util.concurrent.TimeUnit;

import org.budo.selenium.AbstractBudoBrowserDriver;
import org.budo.support.http.client.HttpUtil;
import org.budo.support.lang.util.FileUtil;
import org.budo.time.Time;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.remote.DesiredCapabilities;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
@Getter
@Setter
public class BudoPhantomJSBrowserDriver extends AbstractBudoBrowserDriver {
    public static final String USER_AGENT = "phantomjs.page.settings.userAgent";

    private String phantomPath = this.defaultPhantomPath();

    @Override
    public String pageSource(String url) {
        PhantomJSDriver webDriver = this.getUrl(url);

        String pageSource = webDriver.getPageSource();

        webDriver.close();
        webDriver.quit();

        return pageSource;
    }

    @Override
    public <X> X screenshot(String url, OutputType<X> outputType) {
        log.info("#33 before screenshot, url=" + url + ", outputType=" + outputType);

        PhantomJSDriver webDriver = this.getUrl(url);

        // 指定了OutputType.FILE做为参数传递给getScreenshotAs()方法，其含义是将截取的屏幕以文件形式返回。
        TakesScreenshot takesScreenshot = (TakesScreenshot) webDriver;
        X screenshot = takesScreenshot.getScreenshotAs(outputType);

        log.info("#70 after screenshot, url=" + url + ", outputType=" + outputType);

        webDriver.close();
        webDriver.quit();

        return screenshot;
    }

    public void assertPhantomjs() {
        File phantomjsFile = new File(this.getPhantomPath()); // 指定的文件路径

        PhantomjsSystem phantomjsSystem = PhantomjsSystem.now();
        if (!phantomjsFile.exists()) {
            this.downloadPhantomjsBinary();
            return;
        }

        Long fileSize = FileUtil.fileSize(phantomjsFile);
        if (fileSize < phantomjsSystem.getSize()) { // 不同操作系統 不同大小
            this.downloadPhantomjsBinary();
            return;
        }

        if (!phantomjsFile.canExecute()) {
            throw new RuntimeException("#41 The driver is not executable, phantomjsFile=" + FileUtil.getCanonicalPath(phantomjsFile));
        }

        // log when ok
        if (log.isDebugEnabled()) {
            log.debug("#39 file exists, " + FileUtil.getCanonicalPath(phantomjsFile) + ", size " + fileSize + ", lastModified=" + Time.when(phantomjsFile.lastModified()));
        }
    }

    private DesiredCapabilities desiredCapabilities() {
        DesiredCapabilities desiredCapabilities = new DesiredCapabilities();

        // ssl证书支持
        desiredCapabilities.setCapability("acceptSslCerts", true);

        // 截屏支持
        desiredCapabilities.setCapability("takesScreenshot", true);

        // css搜索支持
        desiredCapabilities.setCapability("cssSelectorsEnabled", true);

        // js支持
        desiredCapabilities.setJavascriptEnabled(true);

        // 驱动支持 phantomjs引擎路径
        File phantomjsFile = new File(this.getPhantomPath()); // 指定的文件路径
        String canonicalPath = FileUtil.getCanonicalPath(phantomjsFile);
        desiredCapabilities.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, canonicalPath);

        return desiredCapabilities;
    }

    private void downloadPhantomjsBinary() {
        PhantomjsSystem phantomjsSystem = PhantomjsSystem.now();
        File phantomjsFile = new File(this.getPhantomPath()); // 指定的文件路径

        log.info("#31 before download " + phantomjsSystem + " to " + FileUtil.getCanonicalPath(phantomjsFile));

        HttpUtil.download(phantomjsSystem.getUrl(), phantomjsFile); // 不同操作系統不同 url

        log.info("#33 after download " + phantomjsSystem + " to " + FileUtil.getCanonicalPath(phantomjsFile));
    }

    protected String defaultPhantomPath() {
        String binPath = "/budo/bin/phantomjs.binary"; // 固定路径

        if (FileUtil.exists(binPath) // 文件存在
                && FileUtil.fileSize(binPath) >= PhantomjsSystem.now().getSize()) { // 文件大小是对的
            return binPath;
        }

        PhantomjsSystem phantomjsSystem = PhantomjsSystem.now(); // 不同操作系統 不同文件名

        // 临时路径
        String tmpDir = System.getProperty("java.io.tmpdir");
        File phantomjsFile = new File(tmpDir + File.separator + "budo" + File.separator + "selenium" + File.separator + "phantomjs" + "." + phantomjsSystem);
        return FileUtil.getCanonicalPath(phantomjsFile);
    }

    private PhantomJSDriver getUrl(String url) {
        this.assertPhantomjs();

        DesiredCapabilities desiredCapabilities = this.desiredCapabilities();
        desiredCapabilities.setCapability(USER_AGENT, this.getUserAgent());

        // 创建无界面浏览器对象
        PhantomJSDriver webDriver = new PhantomJSDriver(desiredCapabilities);
        webDriver.get(url);

        // 设置隐性等待
        webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        return webDriver;
    }
}